﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using AForge.Imaging.Filters;
using System.Drawing.Imaging;

namespace Bildverarbeitung.CGFilter
{
    class SlimeneTaycirFilter : Bildverarbeitung.IFilter
    {
        int r1, r2, r3, g1, g2, g3, b1, b2, b3, length__,
            red = 0,
            blue = 0,
            green = 0;

        Color
            clr__;

        Bitmap
            _bmp,
            result;

        Stack<Bitmap> stck__ = new Stack<Bitmap>();
        Stack<Bitmap> stack_bmp = new Stack<Bitmap>();

        Boolean
            fast_processing = false,     
            optimal_result = true,    
            trace_result = false;    
        byte[] ar, ag, ab;

        BitmapData[] img_data__;
        Bitmap[] images__;

        public Stack<Bitmap> find_mostly_region_stack(Bitmap images_1, Bitmap images_2,
                                            Stack<Bitmap> stack_bmp)
        {
            if ((stack_bmp.Count == 2) || (stack_bmp.Count == 1)) 
            {
                _bmp = stack_bmp.Pop();

                for (int x = 0; x < images_1.Width; x++)
                {
                    for (int y = 182; y < images_1.Height; y++)
                    {
                        clr__ = _bmp.GetPixel(x, y);

                        if (true)
                        {
                            r1 = Convert.ToInt16(images_1.GetPixel(x, y).R);
                            r2 = Convert.ToInt16(images_2.GetPixel(x, y).R);
                            r3 = Convert.ToInt16(clr__.R);

                            g1 = Convert.ToInt16(images_1.GetPixel(x, y).G);
                            g2 = Convert.ToInt16(images_2.GetPixel(x, y).G);
                            g3 = Convert.ToInt16(clr__.G);

                            b1 = Convert.ToInt16(images_1.GetPixel(x, y).B);
                            b2 = Convert.ToInt16(images_2.GetPixel(x, y).B);
                            b3 = Convert.ToInt16(clr__.B);
                        }

                        if (true)
                        {
                            red = (r1 + r2 + r3) / 3;

                            if (optimal_result)
                            {
                                red = the_nearest(
                                    the_bigger(r1, r2, r3),
                                    red,
                                    the_smaller(r1, r2, r3));
                            }

                            green = (g1 + g2 + g3) / 3;

                            if (optimal_result)
                            {
                                green = the_nearest(
                                    the_bigger(g1, g2, g3),
                                    green,
                                    the_smaller(g1, g2, g3));
                            }

                            blue = (b1 + b2 + b3) / 3;

                            if (optimal_result)
                            {
                                blue = the_nearest(
                                    the_bigger(b1, b2, b3),
                                    blue,
                                    the_smaller(b1, b2, b3));
                            }

                            result.SetPixel(x, y, Color.FromArgb(
                                red, green, blue));
                        }

                    }
                    if (x % 200 == 0) Console.Write(".");
                }
                length__--;
                Console.Write(length__);
                if (trace_result)
                {
                    result.Save(
                        "./trace_result_" + System.DateTime.Now.Minute + "_"
                            + System.DateTime.Now.Millisecond + ".jpg",
                        System.Drawing.Imaging.ImageFormat.Jpeg);
                    Console.WriteLine("++" + stack_bmp.Count);
                }
                stck__.Push(result);
                return stck__;
            }
            else 
            {
                //Console.Write(">>" + stack_bmp.Count);
                return find_mostly_region_stack(
                    images_1,
                    images_2,
                    find_mostly_region_stack(stack_bmp.Pop(), stack_bmp.Pop(), stack_bmp));
            }
        }
        public Bitmap GetSummerizedDifferencefromAverage(Bitmap[] images)
        {
            if (true)
            {
                return method_2(images);
            }
            else
            {

              if (images.Length < 3) // nötigen 3 bilder um filter zu nutzen 
                {
                    return null;
                }
            
                else
                {
                    result = images[0].Clone(new Rectangle(0, 0,
                        images[0].Width, images[0].Height), images[0].PixelFormat);

                    if ((images[0].Width < 400) && (images[0].Height < 300))
                        fast_processing = false;

                    ResizeBicubic filter = new ResizeBicubic(400, 300);
                    stack_bmp = new Stack<Bitmap>();

                    for (int i = 0; i < images.Length; i++)
                    {
                        if (fast_processing) stack_bmp.Push(filter.Apply(images[i]));
                        else stack_bmp.Push(images[i]);
                    }
                    length__ = images.Length - 5;

                    Console.Write("beginnen ");
                    result =
                        find_mostly_region_stack(
                                stack_bmp.Pop(),
                                stack_bmp.Pop(),
                                stack_bmp).Pop();
                    Console.WriteLine("beendet");
                    return result;
                }
            }

        }

        public int the_smaller(int a, int b, int c)
        {
            if (a <= b && a <= c) return a;
            if (b <= a && b <= c) return b;
            else return c;
        }

        public int the_bigger(int a, int b, int c)
        {
            if (a >= b && a >= c) return a;
            if (b >= a && b >= c) return b;
            else return c;
        }

        public int the_nearest(int a, int b, int c)
        {
            if ((a - b) <= (b - c)) return a;
            else return b;
        }

        public unsafe Bitmap method_2(Bitmap[] picts)
        {
            ar = new byte[picts.Length];
            ag = new byte[picts.Length];
            ab = new byte[picts.Length];

            img_data__ = new BitmapData[picts.Length + 1];
            images__ = new Bitmap[picts.Length + 1];
            byte*[] img_pointers__ = new byte*[picts.Length + 1];

            Rectangle rec = new Rectangle(new Point(0, 0), picts[0].Size);
            images__[0] = new Bitmap(picts[0].Width, picts[0].Height,
                PixelFormat.Format24bppRgb);
            img_data__[0] =
                images__[0].LockBits(
                rec, ImageLockMode.ReadWrite,
                PixelFormat.Format24bppRgb);

            img_pointers__[0] = (byte*)img_data__[0].Scan0.ToPointer();

            for (short i = 1; i < picts.Length + 1; i++)
            {
                images__[i] = picts[i - 1];
                img_data__[i] =
                    images__[i].LockBits(
                    rec, ImageLockMode.ReadWrite,
                    PixelFormat.Format24bppRgb);

                img_pointers__[i] = (byte*)img_data__[i].Scan0.ToPointer();
            }

            for (short y = 0; y < picts[0].Height; y++)
            {
                for (short x = 0; x < picts[0].Width; x++)
                {
                    for (short i = 1; i < picts.Length; i++)
                    {
                        ab[i - 1] = img_pointers__[i][0];
                        ag[i - 1] = img_pointers__[i][1];
                        ar[i - 1] = img_pointers__[i][2];
                        img_pointers__[i - 1] += 3;
                    }
                    Array.Sort(ab);
                    img_pointers__[0][0] = ab[picts.Length >> 1];
                    Array.Sort(ag);
                    img_pointers__[0][1] = ag[picts.Length >> 1];
                    Array.Sort(ar);
                    img_pointers__[0][2] = ar[picts.Length >> 1];
                }
            }
            images__[0].UnlockBits(img_data__[0]);
            return images__[0];
        }

        public String GetName()
        {
            return ("SlimeneTaycir");
        }
    }
}
